/*
 * Copyright 2023 Huawei Cloud Computing Technology Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.huawei.cloudphoneime;

import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Handler;
import android.os.Message;

import java.io.IOException;

public class CaeImeServer {
    private static final String TAG = "CloudPhoneIme";
    private final String mServerAddress = "CloudPhoneImeChannel";
    private static CaeImeServer gImeServer = null;
    private static final int MSG_NEW_CLIENT = 1;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_NEW_CLIENT:
                    handleNewClientRequest((LocalSocket) msg.obj);
                    break;
                default:
                    break;
            }
        }
    };

    private void handleNewClientRequest(LocalSocket localSocket) {
        if (mRequestListener != null) {
            CaeImeRequest request = new CaeImeRequest(localSocket);
            mRequestListener.onNewRequest(request);
            CaeImeLog.i(TAG, "on new request");
        }
    }

    private CaeImeRequestListener mRequestListener;
    private LocalServerSocket mLocalServerSocket;
    private ServerThread mServerThread;
    private volatile boolean mIsImeServerRun;

    private CaeImeServer() {
        mRequestListener = null;
        mLocalServerSocket = null;
        mServerThread = null;
    }

    public static synchronized CaeImeServer defaultImeServer() {
        if (gImeServer == null) {
            gImeServer = new CaeImeServer();
        }
        return gImeServer;
    }

    public int start() {
        CaeImeLog.i(TAG, "Ime server start.");
        int ret = 0;
        try {
            mLocalServerSocket = new LocalServerSocket(mServerAddress);
            mIsImeServerRun = true;
            mServerThread = new ServerThread();
            mServerThread.start();
        } catch (IOException e) {
            CaeImeLog.e(TAG, "Ime server start error.");
            ret = -1;
        }
        return ret;
    }

    public void stop() {
        CaeImeLog.i(TAG, "Ime server stop.");
        mRequestListener = null;
        mIsImeServerRun = false;

        try {
            LocalSocketAddress serverAddress = new LocalSocketAddress(mServerAddress);
            LocalSocket socket = new LocalSocket();
            socket.connect(serverAddress);
            socket.close();
            mLocalServerSocket.close();
            mServerThread.join();
        } catch (IOException | InterruptedException e) {
            CaeImeLog.e(TAG, "Ime server stop error.");
        }
    }

    public void setRequestListener(CaeImeRequestListener listener) {
        mRequestListener = listener;
    }

    public class ServerThread extends Thread {
        @Override
        public void run() {
            while (mIsImeServerRun) {
                LocalSocket localSocket;
                try {
                    localSocket = mLocalServerSocket.accept();
                } catch (IOException e) {
                    CaeImeLog.e(TAG, "Ime server accept error.");
                    continue;
                }

                if (!mIsImeServerRun) {
                    try {
                        localSocket.close();
                    } catch (IOException e) {
                        CaeImeLog.e(TAG, "Local socket close error.");
                    }
                    CaeImeLog.i(TAG, "Server thread exit.");
                    break;
                }

                Message message = new Message();
                message.what = MSG_NEW_CLIENT;
                message.obj = localSocket;
                mHandler.sendMessage(message);
                CaeImeLog.i(TAG, "Ime Server accept one.");
            }
        }
    }
}